{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "151e244f-09b0-4cd9-a133-a0e9c77ef377",
   "metadata": {},
   "source": [
    "## 中文句子相似度计算\n",
    "使用 MindSpore + MindSpore NLP 实现基于 `bert-base-chinese` 的句子相似度推理。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cb6dafbf-6383-4941-b830-2feb8e8153c6",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[WARNING] DEVICE(6849,e7ffed376020,python):2025-08-03-22:02:03.416.589 [mindspore/ccsrc/utils/dlopen_macro.h:165] DlsymAscend] Dynamically load symbol aclprofGetSupportedFeaturesV2 failed, result = /usr/local/Ascend/ascend-toolkit/latest/lib64/libmsprofiler.so: undefined symbol: aclprofGetSupportedFeaturesV2\n",
      "[WARNING] DEVICE(6849,e7ffed376020,python):2025-08-03-22:02:03.416.721 [mindspore/ccsrc/utils/dlopen_macro.h:165] DlsymAscend] Dynamically load symbol aclrtEventGetTimestamp failed, result = /usr/local/Ascend/ascend-toolkit/latest/lib64/libascendcl.so: undefined symbol: aclrtEventGetTimestamp\n",
      "/usr/local/miniconda3/lib/python3.9/site-packages/numpy/core/getlimits.py:499: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.\n",
      "  setattr(self, word, getattr(machar, word).flat[0])\n",
      "/usr/local/miniconda3/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.\n",
      "  return self._float_to_str(self.smallest_subnormal)\n",
      "/usr/local/miniconda3/lib/python3.9/site-packages/numpy/core/getlimits.py:499: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.\n",
      "  setattr(self, word, getattr(machar, word).flat[0])\n",
      "/usr/local/miniconda3/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.\n",
      "  return self._float_to_str(self.smallest_subnormal)\n",
      "[WARNING] ME(6849:255086382506016,MainProcess):2025-08-03-22:02:09.935.728 [mindspore/context.py:1402] For 'context.set_context', the parameter 'ascend_config' will be deprecated and removed in a future version. Please use the api mindspore.device_context.ascend.op_precision.precision_mode(),\n",
      "                                                       mindspore.device_context.ascend.op_precision.op_precision_mode(),\n",
      "                                                       mindspore.device_context.ascend.op_precision.matmul_allow_hf32(),\n",
      "                                                       mindspore.device_context.ascend.op_precision.conv_allow_hf32(),\n",
      "                                                       mindspore.device_context.ascend.op_tuning.op_compile() instead.\n",
      "Building prefix dict from the default dictionary ...\n",
      "Loading model from cache /tmp/jieba.cache\n",
      "Loading model cost 2.118 seconds.\n",
      "Prefix dict has been built successfully.\n"
     ]
    }
   ],
   "source": [
    "from mindspore import Tensor\n",
    "import mindspore\n",
    "import numpy as np\n",
    "from mindnlp.transformers import BertTokenizer, BertModel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "2009ee2c-2dcc-49c1-afc8-a38eb6d237a5",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/HwHiAiUser/.local/lib/python3.9/site-packages/mindnlp/transformers/tokenization_utils_base.py:1526: FutureWarning: `clean_up_tokenization_spaces` was not set. It will be set to `True` by default. This behavior will be depracted, and will be then set to `False` by default. \n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "# 加载 tokenizer 和模型\n",
    "tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')\n",
    "model = BertModel.from_pretrained('bert-base-chinese')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "22a9db7c-7d1d-42f8-bfe4-796a6e426aec",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义句子相似度函数（使用 [CLS] 向量 + 余弦相似度）\n",
    "def calc_similarity(s1, s2):\n",
    "    inputs1 = tokenizer(s1, return_tensors='ms', padding='max_length', truncation=True, max_length=32)\n",
    "    output1 = model(**inputs1)\n",
    "    emb1 = output1.last_hidden_state[:, 0, :]\n",
    "\n",
    "    inputs2 = tokenizer(s2, return_tensors='ms', padding='max_length', truncation=True, max_length=32)\n",
    "    output2 = model(**inputs2)\n",
    "    emb2 = output2.last_hidden_state[:, 0, :]\n",
    "\n",
    "    vec1 = emb1.asnumpy()[0]\n",
    "    vec2 = emb2.asnumpy()[0]\n",
    "    sim = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))\n",
    "    return sim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b91d9716-d3c1-4527-944b-e39a42573a84",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "相似度：0.9414\n"
     ]
    }
   ],
   "source": [
    "# 输入测试句子（高相似度）\n",
    "s1 = \"我喜欢在假期里去海边度假。\"\n",
    "s2 = \"假期的时候我常常去海边旅游。\"\n",
    "\n",
    "similarity = calc_similarity(s1, s2)\n",
    "print(f\"相似度：{similarity:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "cdcc0f1e-b327-42b9-a7bf-48cd970f55de",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "相似度：0.8608\n"
     ]
    }
   ],
   "source": [
    "# 输入测试句子（中相似度）\n",
    "s1 = \"我喜欢读历史方面的书籍。\"\n",
    "s2 = \"我常常阅读与政治有关的文章。\"\n",
    "\n",
    "similarity = calc_similarity(s1, s2)\n",
    "print(f\"相似度：{similarity:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e9e862d5-72e9-4991-bada-d2927f52919d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "相似度：0.7857\n"
     ]
    }
   ],
   "source": [
    "# 输入测试句子（低相似度）\n",
    "s1 = \"我今天早上吃了煎饼果子。\"\n",
    "s2 = \"昨天晚上下了一场大雨。\"\n",
    "\n",
    "similarity = calc_similarity(s1, s2)\n",
    "print(f\"相似度：{similarity:.4f}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
